<?php

namespace app\common\service\driver;

use app\common\constant\driving\ChannelConstant;
use app\common\constant\driving\CommonConstant;
use app\common\constant\driving\DriverConstant;
use app\common\model\driving\Channel;
use app\common\model\driving\Driver;
use app\common\model\driving\DriverLocation;
use app\common\model\driving\Freight;
use app\common\model\driving\Order;
use app\common\model\driving\OrderReceive;
use app\common\model\driving\OrderServe;
use app\common\model\driving\OrderTrace;
use hichefu\Api;
use think\Db;
use think\Exception;

/**
 * 三方渠道订单服务类
 **/
class OrderReceiveService
{

    /**
     * 三方渠道发单
     *
     * @param array $params {"cipherParam":"加密数据","token":"","tranCode":"KZDJ"}
     * @param string $label 渠道标签
     * @param string $function 类型：receive_order cancel_order order_detail
     * @return mixed
     **/
    public static function receive_order($params, $label, $function)
    {
        user_log($label . '/' . $function, $params);
        $channel = Channel::where('label', $label)
            ->where('status', ChannelConstant::STATUS_1)
            ->field('label,status')
            ->find();
        switch ($label) {
            case 'hichefu':
                $result = self::hichefu_receive_order($params, $label, $function, $channel);
                exit($result);
                break;
        }
    }

    public static function hichefu_receive_order($params, $label, $function, $channel)
    {
        $api = new Api();
        if (!$channel) {
            return $api->encrypt(Api::result(10000, '该渠道不存在或已禁用'));
        }
        $decrypt = $api->decrypt($params['cipherParam']);
        $res = json_decode($decrypt, true);

        $outOrderId = $res['outOrderId'];
        if ($function == 'receive_order') {
            if ($res['operateType'] == 1) {
                // 发单

                $freight = Freight::where('area_code', $res['startAreaId'])->value('id');
                if (!$freight) {
                    return $api->encrypt(Api::result(10000, '该区域没有开通代驾服务'));
                }

                $order_no = '3' . get_order_sn();
                $data = [
                    'channel_label' => $label,
                    'order_id' => $order_no,
                    'out_order_id' => $outOrderId,
                    'data_encrypt' => json_encode($params),
                    'data_decrypt' => $decrypt,
                    'status' => Api::STAGE_1,
                ];
                try {
                    OrderReceive::create($data);
                } catch (Exception $e) {
                    return $api->encrypt(Api::result(10000, $e->getMessage()));
                }

                if (config('site.is_third')) {
                    // 队列
                    // 当前任务将由哪个类来负责处理
                    // 当轮到该任务时，系统将生成一个该类的实例，并调用其fire方法
                    $jobHandlerClassName = '\app\common\job\OrderJob@DistributeOrderRun';
                    // 当前任务所需的业务数据，不能为 resource 类型，其他类型最终将转化为 json 形式的字符串
                    $jobData = ['order_id' => $order_no];
                    // 当前任务归属的队列名称，如果为新队列，会自动创建
                    $jobQueueName = 'kzdriving';
                    \think\Queue::push($jobHandlerClassName, $jobData, $jobQueueName);
                }
            } else {
                // 修改订单信息

                $order_receive = OrderReceive::where('out_order_id', $outOrderId)->find();
                if (!$order_receive) {
                    return $api->encrypt(Api::result(10000, '订单不存在'));
                }
                $order_no = $order_receive['order_id'];
                $order = Order::where('order_id', $order_no)->find();

                $data = [
                    'data_encrypt' => json_encode($params),
                    'data_decrypt' => $decrypt,
                ];
                Db::startTrans();
                try {
                    $order_receive->save($data);
                    if ($order) {
                        $data = self::create_data($order_receive, $decrypt);
                        $order->save($data);
                    }
                    Db::commit();
                } catch (Exception $e) {
                    Db::rollback();
                    return $api->encrypt(Api::result(10000, $e->getMessage()));
                }
            }
            return $api->encrypt(Api::result(200, '', ['orderId' => $order_no]));
        }
        if ($function == 'cancel_order') {
            $order_receive = OrderReceive::where('out_order_id', $outOrderId)->find();
            if (!$order_receive) {
                return $api->encrypt(Api::result(10000, '订单不存在'));
            }
            $order_no = $order_receive['order_id'];

            $data = [
                'cancel_reason' => $res['cancelReason'],
                'status' => Api::STAGE_2,
            ];
            Db::startTrans();
            try {
                $order_receive->save($data);
                $data['end_time'] = date('Y-m-d H:i:s');
                Order::where('order_id', $order_no)->update($data);
                Db::commit();
            } catch (Exception $e) {
                Db::rollback();
                return $api->encrypt(Api::result(10000, $e->getMessage()));
            }
            return $api->encrypt(Api::result(200));
        }
        if ($function == 'order_detail') {
            return $api->encrypt(Api::result(200));
        }
    }

    /**
     * 三方渠道订单分配司机
     *
     * @param string $order_id 订单号
     * @return bool
     **/
    public static function distribute_order($order_id)
    {
        $order_receive = OrderReceive::where('order_id', $order_id)->find();
        if (!$order_receive) {
            throw new Exception('订单不存在');
        }
        if ($order_receive['status'] != Api::STAGE_1) {
            throw new Exception('订单状态不是已受理');
        }
        $decrypt = json_decode($order_receive['data_decrypt'], true);

        $data = self::create_data($order_receive, $decrypt);

        $driver = self::distribute_driver($decrypt['startLat'], $decrypt['startLng']);
        Db::startTrans();
        try {
            if ($driver['code']) {
                $data['status'] = Api::STAGE_11;
                $data['driver_id'] = $driver['driver']['id'];
                $data['accept_time'] = date('Y-m-d H:i:s');
                $order_receive->status = Api::STAGE_11;
                $order_receive->save();
            } else {
                $data['status'] = Api::STAGE_1;
            }
            $order = Order::create($data);
            $item_data = [
                'oid' => $order->id,
            ];
            OrderServe::create($item_data);
            if ($driver['code']) {
                Driver::where('id', $driver['driver']['id'])->update($item_data);
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            throw new Exception($e->getMessage());
        }

        try {
            self::driving($order['channel_label'], 'updateOrderStatus', $data['status'], $data, $driver);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        return true;
    }

    /**
     * 组装订单数据
     *
     * @param mixed $order_receive
     * @param array $decrypt
     * @return array
     **/
    public static function create_data($order_receive, $decrypt)
    {
        $avatar = CommonConstant::AVATAR;
        $mileage = 0;
        $total_fee = 0;
        $driver_amount = 0;
        $data = [
            'channel_label' => $order_receive['channel_label'],
            'order_id' => $order_receive['order_id'],
            'out_order_id' => $decrypt['outOrderId'],
            'avatar' => $avatar,
            'user_name' => $decrypt['userName'],
            'user_phone' => $decrypt['userPhone'],
            'start_area_id' => $decrypt['startAreaId'],
            'start_lat' => $decrypt['startLat'],
            'start_lng' => $decrypt['startLng'],
            'start_poi_name' => $decrypt['startPoiName'],
            'start_address' => $decrypt['startAddress'],
            'end_area_id' => $decrypt['endAreaId'],
            'end_lat' => $decrypt['endLat'],
            'end_lng' => $decrypt['endLng'],
            'end_poi_name' => $decrypt['endPoiName'],
            'end_address' => $decrypt['endAddress'],
            'appointment_time' => isset($decrypt['appointmentTime']) ? $decrypt['appointmentTime'] : 0,
            'pay_type' => $decrypt['payType'],
            'rights_id' => $decrypt['rightsId'],
            'service_type' => $decrypt['serviceType'],
            'createtime' => $order_receive['createtime'],
            'mileage' => $mileage,
            'total_fee' => $total_fee,
            'driver_amount' => $driver_amount,
        ];
        return $data;
    }

    /**
     * 分配司机
     *
     * @param float $lat 纬度
     * @param float $lng 经度
     * @return array
     **/
    public static function distribute_driver($lat, $lng)
    {
        $code = 0;
        $driver = [];
        $location = [];

        $around_distance = config('site.around_distance');
        $convert = new \convert\convert();
        $area = $convert->getAround($lat, $lng, $around_distance * 1000);
        $where = [];
        $where['lng'] = ['BETWEEN', [$area['minLng'], $area['maxLng']]];
        $where['lat'] = ['BETWEEN', [$area['minLat'], $area['maxLat']]];
        $field = "driver_id,lng,lat,(POWER(MOD(ABS(lng - " . $lng . "),360),2) + POWER(ABS(lat - " . $lat . "),2)) AS distance";
        $location_list = DriverLocation::whereRaw('lng IS NOT NULL')
            ->where($where)
            ->field($field)
            ->order('distance asc')
            ->select();
        if ($location_list) {
//            foreach ($location_list as $key=>$val){
//                $distance = $convert->getDistance($lng,$lat,$val['lng'],$val['lat']);
//                $val['m_distance'] = $distance['distance'];
//                $val['km_distance'] = $distance['km_distance'];
//            }
            $location_object = array_column($location_list, null, 'driver_id');
            $location_data = [];
            $driver_list = Driver::where('id', 'in', array_keys($location_object))
                ->where('is_online', DriverConstant::ONLINE_1)
                ->where('oid', 0)
                ->where('money', 'gt', config('site.order_receive_money'))
                ->select();
            if ($driver_list) {
                $driver_object = array_column($driver_list, null, 'id');
                foreach ($location_list as $key => $val) {
                    if (array_key_exists($val['driver_id'], $driver_object)) {
                        $location_data[] = $val;
                    }
                }

                $code = 1;
                $driver = $driver_object[$location_data[0]['driver_id']];
                $location = $location_data[0];
            }
        }
        return compact('code', 'driver', 'location');
    }


    /**
     * 三方接口
     *
     * @param string $label
     * @param string $function
     * @param integer $status
     * @param array $order
     * @param array $custom ['driver','location','trace']
     * @return mixed
     **/
    public static function driving($label, $function, $status, $order, $custom = [])
    {
        if (config('site.is_third') == 0) {
            return true;
        }

        $is_third = ChannelService::is_third($label);
        if (!$is_third) {
            return true;
        }

        if ($status == Api::STAGE_1) {
            return true;
        }

        self::$label($label, $function, $status, $order, $custom);
    }

    public static function hichefu($label, $function, $status, $order, $custom)
    {
        $params = [
            'outOrderId' => $order['out_order_id'], // 平台订单id
            'orderId' => $order['order_id'], // 服务商订单id
        ];
        if ($function == 'updateOrderStatus') {
            if ($status == Api::STAGE_11) {
                $driver = $custom['driver'];
                $location = isset($custom['location']) && !empty($custom['location']) ? $custom['location'] : [];
                if (!$location) {
                    $location = DriverLocation::where('driver_id', $driver['id'])->find();
                }
                $driverInfo = [
                    'driverName' => $driver['nickname'], // 司机姓名，⻓度8个字符以内
                    'contactPhone' => $driver['mobile'], // 明⽂传输，不允许为固定电话或其他格式的电话
                    'lng' => $location['lng'], // 司机位置经度，接单时必填
                    'lat' => $location['lat'], // 司机位置纬度，接单时必填
                    'driverCode' => $driver['code'], // 司机⼯号，⻓度16个字符以内
                    'starLevel' => $driver['level'], // 5分制，表示师傅在服务商系统内的服务星级。
                    'drivingYears' => $driver['year'], // 司机驾龄
                    'serviceTimes' => $driver['order_num'], // 司机代驾次数
                    'headImg' => $driver['avatar'], // 司机头像照⽚地址，公⽹可访问的地址，图⽚⼤⼩为压缩格式，请尽量减⼩此⽂件体积，便于加载。
                ];
                $params['driverInfo'] = $driverInfo;// 接单司机信息 11 已接单状态时必填
            }
            $params['status'] = $status; // 订单状态
            $params['time'] = date('Y-m-d H:i:s'); // 状态变更时间 yyyy-MM-dd HH:mm:ss
        }
        if ($function == 'updateDriverLocation') {
            // 参数格式 locationList:[{"outOrderId":"1234","orderId":"123","lat":"12.123","lng":"1.4234"}]
        }
        if ($function == 'submitOrderBill') {
            $trace_data = $custom['trace'];
            $serviceInfo = [
                'acceptTime' => bcmul($order['accept_time'], 1000), // 接单时间（毫秒）
                'startTime' => bcmul($order['start_time'], 1000), // 开始代驾时间（毫秒）
                'endTime' => bcmul(time(), 1000), // 结束代驾时间（毫秒）
                'distance' => $trace_data['distance'], // 代驾⾥程，单位km
//                        'waitTime' => 0, // 等候时间，单位分钟
            ];
            $orderFee = [
                'totalFee' => $trace_data['total_fee'], // 总⾦额
//                        'rightsFee' => 0, // 权益抵扣⾦额
//                        'userPayFee' => 0, // ⽤户需付⾦额
                'feeDetails' => [
                    'feeType' => Api::COST_2, // 费⽤类型
                    'fee' => $trace_data['total_fee'], // 费⽤⾦额
                    'feeRemark' => '', // 费⽤补充说明
                ], // 费⽤明细
            ];
            $params['operateType'] = 1; // 1-新单上报 2-账单修改
            $params['serviceInfo'] = $serviceInfo; // ⾏程服务详情
            $params['orderFee'] = $orderFee; // 订单费⽤明细
        }
        if ($function == 'getTotalFee') {
        }

        $addon = self::$addons[$label];
        $api = new $addon;
        try {
            $result = $api->$function($params);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        return $result;
    }

    public static $addons = [
        'hichefu' => 'hichefu\Api',
    ];

}
